/******************************************************************************
*                        ETSI TS 103 634 V1.1.1                               *
*              Low Complexity Communication Codec Plus (LC3plus)              *
*                                                                             *
* Copyright licence is solely granted through ETSI Intellectual Property      *
* Rights Policy, 3rd April 2019. No patent licence is granted by implication, *
* estoppel or otherwise.                                                      *
******************************************************************************/


#include "cfft.h"
#include "iisfft.h" /* for M_PIl  */
#include <stdlib.h> /* for abs() */
#include <assert.h>

#define MAX_FFT_SIZE 1024
#define MAX_TRIGDATA_SIZE (MAX_FFT_SIZE / 2)

/**
 * \brief table aTrigData

          Generate table:  aTrigData[i] = sin( pi * i / (2*MAX_TRIGDATA_SIZE) );   i = 0, ... MAX_TRIGDATA_SIZE
 */
static const LC3_FLOAT static_table[MAX_TRIGDATA_SIZE + 1] = {
    0.0000000000e+000, 3.0679567717e-003, 6.1358846724e-003, 9.2037543654e-003, 1.2271538377e-002,
    1.5339205973e-002, 1.8406730145e-002, 2.1474080160e-002, 2.4541229010e-002, 2.7608145028e-002,
    3.0674804002e-002, 3.3741172403e-002, 3.6807224154e-002, 3.9872925729e-002, 4.2938258499e-002,
    4.6003181487e-002, 4.9067676067e-002, 5.2131704986e-002, 5.5195245892e-002, 5.8258265257e-002,
    6.1320737004e-002, 6.4382627606e-002, 6.7443922162e-002, 7.0504575968e-002, 7.3564566672e-002,
    7.6623864472e-002, 7.9682439566e-002, 8.2740262151e-002, 8.5797309875e-002, 8.8853552938e-002,
    9.1908954084e-002, 9.4963498414e-002, 9.8017141223e-002, 1.0106986016e-001, 1.0412163287e-001,
    1.0717242211e-001, 1.1022220552e-001, 1.1327095330e-001, 1.1631862819e-001, 1.1936521530e-001,
    1.2241067737e-001, 1.2545497715e-001, 1.2849810719e-001, 1.3154003024e-001, 1.3458070159e-001,
    1.3762012124e-001, 1.4065824449e-001, 1.4369502664e-001, 1.4673046768e-001, 1.4976453781e-001,
    1.5279719234e-001, 1.5582840145e-001, 1.5885815024e-001, 1.6188639402e-001, 1.6491311789e-001,
    1.6793829203e-001, 1.7096188664e-001, 1.7398387194e-001, 1.7700421810e-001, 1.8002289534e-001,
    1.8303988874e-001, 1.8605515361e-001, 1.8906866014e-001, 1.9208039343e-001, 1.9509032369e-001,
    1.9809840620e-001, 2.0110464096e-001, 2.0410896838e-001, 2.0711137354e-001, 2.1011184156e-001,
    2.1311031282e-001, 2.1610680223e-001, 2.1910123527e-001, 2.2209362686e-001, 2.2508391738e-001,
    2.2807207704e-001, 2.3105810583e-001, 2.3404195905e-001, 2.3702360690e-001, 2.4000301957e-001,
    2.4298018217e-001, 2.4595504999e-001, 2.4892760813e-001, 2.5189781189e-001, 2.5486564636e-001,
    2.5783109665e-001, 2.6079410315e-001, 2.6375466585e-001, 2.6671275496e-001, 2.6966831088e-001,
    2.7262136340e-001, 2.7557182312e-001, 2.7851969004e-001, 2.8146493435e-001, 2.8440752625e-001,
    2.8734746575e-001, 2.9028466344e-001, 2.9321914911e-001, 2.9615089297e-001, 2.9907983541e-001,
    3.0200594664e-001, 3.0492922664e-001, 3.0784964561e-001, 3.1076714396e-001, 3.1368175149e-001,
    3.1659337878e-001, 3.1950202584e-001, 3.2240769267e-001, 3.2531028986e-001, 3.2820984721e-001,
    3.3110630512e-001, 3.3399966359e-001, 3.3688986301e-001, 3.3977687359e-001, 3.4266072512e-001,
    3.4554132819e-001, 3.4841868281e-001, 3.5129275918e-001, 3.5416352749e-001, 3.5703095794e-001,
    3.5989505053e-001, 3.6275571585e-001, 3.6561298370e-001, 3.6846682429e-001, 3.7131720781e-001,
    3.7416407466e-001, 3.7700742483e-001, 3.7984719872e-001, 3.8268342614e-001, 3.8551604748e-001,
    3.8834503293e-001, 3.9117038250e-001, 3.9399203658e-001, 3.9680999517e-001, 3.9962419868e-001,
    4.0243464708e-001, 4.0524131060e-001, 4.0804415941e-001, 4.1084316373e-001, 4.1363832355e-001,
    4.1642954946e-001, 4.1921690106e-001, 4.2200025916e-001, 4.2477968335e-001, 4.2755508423e-001,
    4.3032649159e-001, 4.3309381604e-001, 4.3585708737e-001, 4.3861624599e-001, 4.4137126207e-001,
    4.4412213564e-001, 4.4686883688e-001, 4.4961133599e-001, 4.5234957337e-001, 4.5508357882e-001,
    4.5781329274e-001, 4.6053871512e-001, 4.6325978637e-001, 4.6597650647e-001, 4.6868881583e-001,
    4.7139674425e-001, 4.7410020232e-001, 4.7679921985e-001, 4.7949376702e-001, 4.8218378425e-001,
    4.8486924171e-001, 4.8755016923e-001, 4.9022647738e-001, 4.9289819598e-001, 4.9556526542e-001,
    4.9822765589e-001, 5.0088536739e-001, 5.0353837013e-001, 5.0618666410e-001, 5.0883013010e-001,
    5.1146882772e-001, 5.1410275698e-001, 5.1673179865e-001, 5.1935601234e-001, 5.2197527885e-001,
    5.2458965778e-001, 5.2719914913e-001, 5.2980363369e-001, 5.3240311146e-001, 5.3499764204e-001,
    5.3758704662e-001, 5.4017144442e-001, 5.4275077581e-001, 5.4532498121e-001, 5.4789406061e-001,
    5.5045795441e-001, 5.5301672220e-001, 5.5557024479e-001, 5.5811852217e-001, 5.6066155434e-001,
    5.6319934130e-001, 5.6573182344e-001, 5.6825894117e-001, 5.7078075409e-001, 5.7329714298e-001,
    5.7580816746e-001, 5.7831376791e-001, 5.8081394434e-001, 5.8330863714e-001, 5.8579784632e-001,
    5.8828157187e-001, 5.9075969458e-001, 5.9323227406e-001, 5.9569931030e-001, 5.9816068411e-001,
    6.0061645508e-001, 6.0306662321e-001, 6.0551106930e-001, 6.0794979334e-001, 6.1038279533e-001,
    6.1281007528e-001, 6.1523157358e-001, 6.1764729023e-001, 6.2005722523e-001, 6.2246125937e-001,
    6.2485951185e-001, 6.2725180387e-001, 6.2963825464e-001, 6.3201874495e-001, 6.3439327478e-001,
    6.3676184416e-001, 6.3912445307e-001, 6.4148104191e-001, 6.4383155107e-001, 6.4617604017e-001,
    6.4851438999e-001, 6.5084666014e-001, 6.5317285061e-001, 6.5549284220e-001, 6.5780669451e-001,
    6.6011434793e-001, 6.6241580248e-001, 6.6471099854e-001, 6.6699993610e-001, 6.6928261518e-001,
    6.7155897617e-001, 6.7382901907e-001, 6.7609268427e-001, 6.7835003138e-001, 6.8060100079e-001,
    6.8284553289e-001, 6.8508368731e-001, 6.8731534481e-001, 6.8954056501e-001, 6.9175922871e-001,
    6.9397145510e-001, 6.9617712498e-001, 6.9837623835e-001, 7.0056879520e-001, 7.0275473595e-001,
    7.0493406057e-001, 7.0710676908e-001, 7.0927280188e-001, 7.1143221855e-001, 7.1358484030e-001,
    7.1573084593e-001, 7.1787005663e-001, 7.2000253201e-001, 7.2212821245e-001, 7.2424709797e-001,
    7.2635912895e-001, 7.2846436501e-001, 7.3056274652e-001, 7.3265427351e-001, 7.3473888636e-001,
    7.3681658506e-001, 7.3888731003e-001, 7.4095112085e-001, 7.4300795794e-001, 7.4505776167e-001,
    7.4710059166e-001, 7.4913638830e-001, 7.5116515160e-001, 7.5318682194e-001, 7.5520139933e-001,
    7.5720882416e-001, 7.5920921564e-001, 7.6120239496e-001, 7.6318842173e-001, 7.6516723633e-001,
    7.6713889837e-001, 7.6910334826e-001, 7.7106052637e-001, 7.7301043272e-001, 7.7495312691e-001,
    7.7688848972e-001, 7.7881652117e-001, 7.8073722124e-001, 7.8265058994e-001, 7.8455656767e-001,
    7.8645521402e-001, 7.8834640980e-001, 7.9023021460e-001, 7.9210656881e-001, 7.9397547245e-001,
    7.9583692551e-001, 7.9769086838e-001, 7.9953724146e-001, 8.0137616396e-001, 8.0320751667e-001,
    8.0503135920e-001, 8.0684757233e-001, 8.0865615606e-001, 8.1045717001e-001, 8.1225061417e-001,
    8.1403630972e-001, 8.1581443548e-001, 8.1758481264e-001, 8.1934750080e-001, 8.2110249996e-001,
    8.2284981012e-001, 8.2458931208e-001, 8.2632106543e-001, 8.2804507017e-001, 8.2976120710e-001,
    8.3146959543e-001, 8.3317017555e-001, 8.3486288786e-001, 8.3654773235e-001, 8.3822470903e-001,
    8.3989381790e-001, 8.4155499935e-001, 8.4320825338e-001, 8.4485358000e-001, 8.4649091959e-001,
    8.4812033176e-001, 8.4974175692e-001, 8.5135519505e-001, 8.5296058655e-001, 8.5455799103e-001,
    8.5614734888e-001, 8.5772860050e-001, 8.5930180550e-001, 8.6086696386e-001, 8.6242395639e-001,
    8.6397284269e-001, 8.6551362276e-001, 8.6704623699e-001, 8.6857068539e-001, 8.7008696795e-001,
    8.7159508467e-001, 8.7309497595e-001, 8.7458664179e-001, 8.7607008219e-001, 8.7754529715e-001,
    8.7901222706e-001, 8.8047087193e-001, 8.8192129135e-001, 8.8336336613e-001, 8.8479709625e-001,
    8.8622254133e-001, 8.8763964176e-001, 8.8904833794e-001, 8.9044874907e-001, 8.9184069633e-001,
    8.9322429895e-001, 8.9459949732e-001, 8.9596623182e-001, 8.9732456207e-001, 8.9867448807e-001,
    9.0001589060e-001, 9.0134882927e-001, 9.0267330408e-001, 9.0398931503e-001, 9.0529674292e-001,
    9.0659570694e-001, 9.0788608789e-001, 9.0916800499e-001, 9.1044127941e-001, 9.1170603037e-001,
    9.1296219826e-001, 9.1420978308e-001, 9.1544872522e-001, 9.1667908430e-001, 9.1790080070e-001,
    9.1911387444e-001, 9.2031830549e-001, 9.2151403427e-001, 9.2270112038e-001, 9.2387950420e-001,
    9.2504924536e-001, 9.2621022463e-001, 9.2736250162e-001, 9.2850607634e-001, 9.2964088917e-001,
    9.3076694012e-001, 9.3188428879e-001, 9.3299281597e-001, 9.3409252167e-001, 9.3518352509e-001,
    9.3626564741e-001, 9.3733900785e-001, 9.3840354681e-001, 9.3945920467e-001, 9.4050604105e-001,
    9.4154405594e-001, 9.4257318974e-001, 9.4359344244e-001, 9.4460481405e-001, 9.4560730457e-001,
    9.4660091400e-001, 9.4758558273e-001, 9.4856137037e-001, 9.4952815771e-001, 9.5048606396e-001,
    9.5143502951e-001, 9.5237499475e-001, 9.5330601931e-001, 9.5422810316e-001, 9.5514118671e-001,
    9.5604526997e-001, 9.5694035292e-001, 9.5782643557e-001, 9.5870345831e-001, 9.5957154036e-001,
    9.6043050289e-001, 9.6128046513e-001, 9.6212142706e-001, 9.6295326948e-001, 9.6377605200e-001,
    9.6458977461e-001, 9.6539443731e-001, 9.6618998051e-001, 9.6697646379e-001, 9.6775382757e-001,
    9.6852207184e-001, 9.6928125620e-001, 9.7003126144e-001, 9.7077214718e-001, 9.7150391340e-001,
    9.7222650051e-001, 9.7293996811e-001, 9.7364425659e-001, 9.7433936596e-001, 9.7502535582e-001,
    9.7570210695e-001, 9.7636973858e-001, 9.7702813148e-001, 9.7767734528e-001, 9.7831737995e-001,
    9.7894817591e-001, 9.7956979275e-001, 9.8018211126e-001, 9.8078525066e-001, 9.8137921095e-001,
    9.8196387291e-001, 9.8253929615e-001, 9.8310548067e-001, 9.8366242647e-001, 9.8421007395e-001,
    9.8474848270e-001, 9.8527765274e-001, 9.8579752445e-001, 9.8630809784e-001, 9.8680937290e-001,
    9.8730140924e-001, 9.8778414726e-001, 9.8825758696e-001, 9.8872166872e-001, 9.8917651176e-001,
    9.8962199688e-001, 9.9005818367e-001, 9.9048507214e-001, 9.9090266228e-001, 9.9131083488e-001,
    9.9170976877e-001, 9.9209928513e-001, 9.9247956276e-001, 9.9285042286e-001, 9.9321192503e-001,
    9.9356412888e-001, 9.9390697479e-001, 9.9424046278e-001, 9.9456459284e-001, 9.9487930536e-001,
    9.9518471956e-001, 9.9548077583e-001, 9.9576741457e-001, 9.9604469538e-001, 9.9631261826e-001,
    9.9657112360e-001, 9.9682027102e-001, 9.9706006050e-001, 9.9729043245e-001, 9.9751144648e-001,
    9.9772304296e-001, 9.9792528152e-001, 9.9811810255e-001, 9.9830156565e-001, 9.9847555161e-001,
    9.9864023924e-001, 9.9879544973e-001, 9.9894130230e-001, 9.9907773733e-001, 9.9920475483e-001,
    9.9932235479e-001, 9.9943059683e-001, 9.9952942133e-001, 9.9961882830e-001, 9.9969881773e-001,
    9.9976938963e-001, 9.9983060360e-001, 9.9988234043e-001, 9.9992471933e-001, 9.9995762110e-001,
    9.9998116493e-001, 9.9999529123e-001, 1.0000000000e+000};

/**
 * \brief scramble
          The function sorts the complex vector re/im of length n from 'in-order' to 'bitreversed order'.

 * \param[i/o] re:   real input
 * \param[i/o] im:   imag input
 * \param[i  ] n:    size of fft
 * \param[i  ] s:    stride of real and imag input

 * \return none
 */
static void scramble(LC3_FLOAT* re, LC3_FLOAT* im, LC3_INT32 n, LC3_INT32 s)
{
  LC3_FLOAT tmp;
  LC3_INT32 m, k, j;

    for (m = 1, j = 0; m < (n - 1); m++) {
        {
            for (k = n >> 1; (!((j ^= k) & k)); k >>= 1)
                ;
        }

    if (j > m) {
            tmp = re[s * m];
            re[s * m] = re[s * j];
            re[s * j] = tmp;

            tmp = im[s * m];
            im[s * m] = im[s * j];
            im[s * j] = tmp;
    }
  }
}

/**
 * \brief fft
          The function performs a radix-2, decimation in time complex fft. The calculation takes place inplace.
          The real and imaginary part can reside in separate buffers as well as interleaved in one buffer. The
          stride length has to be set accordingly.

 * \param[i/o] re:          real input / real output
 * \param[i/o] im:          imag input / imag output
 * \param[i  ] sizeOfFft:   size of fft
 * \param[i  ] s:           stride of real and imag input / output

 * \return none
 */
static void fft(const LC3_FLOAT* aTrigData, LC3_INT32 trigdata_size, LC3_FLOAT* re, LC3_FLOAT* im, LC3_INT32 sizeOfFft, LC3_INT32 s)
{
  LC3_INT32 trigstep, i, ldm, n;
  LC3_INT32 trigDataSize;
  LC3_INT32 ldn = 0;

    trigDataSize = sizeOfFft / 2;

  while (sizeOfFft >>= 1) {
    ldn++;
  }

    n = 1 << ldn;

    scramble(re, im, n, s);

  /* 1+2 stage implemented as radix 4 */
    for (i = 0; i < n; i += 4) {
    LC3_FLOAT a00, a01, a10, a11;
    LC3_FLOAT a20, a21, a30, a31;

        a00 = re[s * (i + 0)] + re[s * (i + 1)];
        a10 = re[s * (i + 2)] + re[s * (i + 3)];
        a20 = im[s * (i + 0)] + im[s * (i + 1)];
        a30 = im[s * (i + 2)] + im[s * (i + 3)];

        a01 = re[s * (i + 0)] - re[s * (i + 1)];
        a21 = re[s * (i + 2)] - re[s * (i + 3)];
        a31 = im[s * (i + 0)] - im[s * (i + 1)];
        a11 = im[s * (i + 2)] - im[s * (i + 3)];

        re[s * (i + 0)] = a00 + a10;
        re[s * (i + 2)] = a00 - a10;
        im[s * (i + 0)] = a20 + a30;
        im[s * (i + 2)] = a20 - a30;
        re[s * (i + 1)] = a11 + a01;
        re[s * (i + 3)] = a01 - a11;
        im[s * (i + 1)] = a31 - a21;
        im[s * (i + 3)] = a21 + a31;
  }

  /* next stages implemented as radix 2 */
    for (ldm = 3; ldm <= ldn; ++ldm) {
        const LC3_INT32 m = (1 << ldm);
        const LC3_INT32 mh = (m >> 1);
        LC3_INT32 j, r;

        trigstep = ((trigDataSize * 4) >> ldm) * trigdata_size / trigDataSize;

        for (j = 0; j < mh / 2; ++j) {
      LC3_FLOAT c1, c2;

            c2 = aTrigData[j * trigstep];
            c1 = aTrigData[trigdata_size - j * trigstep];

            for (r = 0; r < n; r += m) {
        LC3_FLOAT vr, vi, ur, ui;

                LC3_INT32 t0 = r + j;
                LC3_INT32 t1 = s * t0;
                LC3_INT32 t2 = s * (t0 + mh);

                vr = re[t2] * c1 + im[t2] * c2;
        vi = -re[t2] * c2 + im[t2] * c1;

        ur = re[t1];
        ui = im[t1];

        re[t1] = re[t1] + vr;
        im[t1] = im[t1] + vi;

        re[t2] = ur - vr;
        im[t2] = ui - vi;

                t0 = r + j + mh / 2;
                t1 = s * t0;
                t2 = s * (t0 + mh);

        vr = -re[t2] * c2 + im[t2] * c1;
        vi = -re[t2] * c1 - im[t2] * c2;

        ur = re[t1];
        ui = im[t1];
        re[t1] = re[t1] + vr;
        im[t1] = im[t1] + vi;

        re[t2] = ur - vr;
        im[t2] = ui - vi;
      }
    }
  }
}

/**
 * \brief ifft
          The function performs a radix-2, decimation in time complex inverse fft. The calculation takes place
          inplace. The real and imaginary part can reside in separate buffers as well as interleaved in one buffer.
          The stride length has to be set accordingly.

 * \param[i/o] re:          real input / real output
 * \param[i/o] im:          imag input / imag output
 * \param[i  ] sizeOfFft:   size of fft
 * \param[i  ] s:           stride of real and imag input / output

 * \return none
 */
static void ifft(const LC3_FLOAT* aTrigData, LC3_INT32 trigdata_size, LC3_FLOAT* re, LC3_FLOAT* im, LC3_INT32 sizeOfFft, LC3_INT32 s)
{
    LC3_INT32 trigstep, i, ldm, n;
  LC3_INT32 trigDataSize;
  LC3_INT32 ldn = 0;

  trigDataSize = sizeOfFft;

  while (sizeOfFft >>= 1) {
    ldn++;
  }

    n = 1 << ldn;

    scramble(re, im, n, s);

  /* 1+2 stage radix 4 */
    for (i = 0; i < n; i += 4) {
    LC3_FLOAT a00, a01, a10, a11;
    LC3_FLOAT a20, a21, a30, a31;

        a00 = re[s * (i + 0)] + re[s * (i + 1)];
        a10 = re[s * (i + 2)] + re[s * (i + 3)];
        a20 = im[s * (i + 0)] + im[s * (i + 1)];
        a30 = im[s * (i + 2)] + im[s * (i + 3)];

        a01 = re[s * (i + 0)] - re[s * (i + 1)];
        a21 = re[s * (i + 2)] - re[s * (i + 3)];
        a31 = im[s * (i + 0)] - im[s * (i + 1)];
        a11 = im[s * (i + 2)] - im[s * (i + 3)];

        re[s * (i + 0)] = a00 + a10;
        re[s * (i + 2)] = a00 - a10;
        im[s * (i + 0)] = a20 + a30;
        im[s * (i + 2)] = a20 - a30;

        re[s * (i + 1)] = a01 - a11;
        re[s * (i + 3)] = a01 + a11;
        im[s * (i + 1)] = a31 + a21;
        im[s * (i + 3)] = a31 - a21;
  }

    for (ldm = 3; ldm <= ldn; ++ldm) {
        const LC3_INT32 m = (1 << ldm);
        const LC3_INT32 mh = (m >> 1);
        LC3_INT32 j, r;

        trigstep = ((trigDataSize * 4) >> ldm) * trigdata_size / trigDataSize;

        for (j = 0; j < mh / 2; ++j) {
      LC3_FLOAT c1, c2;

            c2 = aTrigData[j * trigstep];
            c1 = aTrigData[trigdata_size - j * trigstep];

            for (r = 0; r < n; r += m) {
        LC3_FLOAT vr, vi, ur, ui;

                LC3_INT32 t0 = r + j;
                LC3_INT32 t1 = s * t0;
                LC3_INT32 t2 = s * (t0 + mh);

        vr = re[t2] * c1 - im[t2] * c2;
        vi = re[t2] * c2 + im[t2] * c1;

        ur = re[t1];
        ui = im[t1];

        re[t1] = ur + vr;
        im[t1] = ui + vi;

        re[t2] = ur - vr;
        im[t2] = ui - vi;

                t0 = r + j + mh / 2;
                t1 = s * t0;
                t2 = s * (t0 + mh);

        vr = -re[t2] * c2 - im[t2] * c1;
                vi = re[t2] * c1 - im[t2] * c2;

        ur = re[t1];
        ui = im[t1];

        re[t1] = ur + vr;
        im[t1] = ui + vi;
        re[t2] = ur - vr;
        im[t2] = ui - vi;
      }
    }
  }
}

/**
 * \brief cfft
          The function serves as wrapper for the forward and inverse fft.

 * \param[i/o] re:          real input / real output
 * \param[i/o] im:          imag input / imag output
 * \param[i  ] sizeOfFft:   size of fft
 * \param[i  ] s:           stride of real and imag input / output
 * \param[i  ] iSign:       forward fft: -1 / inverse fft: 1

 * \return none
 */
void LC3_cfft(LC3_FLOAT* re, LC3_FLOAT* im, LC3_INT32 length, LC3_INT32 stride, LC3_INT32 sign)
{
    assert(abs(sign) == 1);
    assert(CFFT_SUPPORT(length));

    if (sign == -1) {
        fft(static_table, MAX_TRIGDATA_SIZE, re, im, length, stride);
    } else {
        ifft(static_table, MAX_TRIGDATA_SIZE, re, im, length, stride);
    }
}

LC3_INT32 LC3_cfft_plan(Cfft* handle, LC3_INT32 length, LC3_INT32 sign)
{
    /* check if length is power of two */
    if (!CFFT_PLAN_SUPPORT(length) || abs(sign) != 1)
        return 0;

    handle->len = length;
    handle->sign = sign;

    if (length <= MAX_FFT_SIZE) {
        handle->table = NULL;
    } else {
        LC3_INT32 i = 0;
        handle->table = (LC3_FLOAT*)malloc((length / 2 + 1) * sizeof(LC3_FLOAT));
        for (i = 0; i < length / 2 + 1; i++) {
            handle->table[i] = (LC3_FLOAT)LC3_SIN(M_PIl * i / length);
        }
    }
    return 1;
  }

void LC3_cfft_apply(Cfft* handle, LC3_FLOAT* re, LC3_FLOAT* im, LC3_INT32 stride)
{
    if (handle->len <= MAX_FFT_SIZE) {
        LC3_cfft(re, im, handle->len, stride, handle->sign);
    } else if (handle->sign == -1) {
        fft(handle->table, handle->len / 2, re, im, handle->len, stride);
    } else {
        ifft(handle->table, handle->len / 2, re, im, handle->len, stride);
  }
}

void LC3_cfft_free(Cfft* handle) 
{ 
  if(handle->table)
    free(handle->table); 
}
